#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__

#include <iostream>
#include <string>
#include <cstring>
#include <memory>

#include <sys/socket.h> // socket
#include <netinet/in.h> // struct sockaddr_in
#include <arpa/inet.h>	// htons

#include "Log.hpp"
#include "Comm.hpp"


using namespace LogModule;
const static int gsockfd = -1;
const static std::string gdefaultip = "127.0.0.1"; // 表示本地主机
const static uint16_t gdefaultport = 8080;		   // 设置端口号

class UdpServer
{
public:
	UdpServer(const uint16_t port = gdefaultport)
		:_port(port), _sockfd(gsockfd), _isrunning(false)
	{
	}
	void InitServer()
	{
		// 创建套接字
		_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
		if (_sockfd < 0)
		{
			LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
			Die(1);
		}
		LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;
		
		// 2. 填充网络信息，并bind绑定
		// 2.1 有没有把socket信息，设置进入内核中？？没有，只是填充了结构体！
		struct sockaddr_in local;
		bzero(&local, sizeof(local));
		local.sin_family = AF_INET;
		local.sin_port = ::htons(_port);				  // 本地发送给网络 是要把端口哈发出去，要把小段变大端
		// local.sin_addr.s_addr = ::inet_addr(_ip.c_str()); // 1. string ip->4bytes 2. network order  ip要转换成四字节，并发到网络要转换大小端

		// 表示接受该服务器上所有IP地址发来的信息
		local.sin_addr.s_addr = INADDR_ANY;

		// bind 设置到内核
		int n = bind(_sockfd, CONV(&local), sizeof(local));
		if (n < 0)
		{
			LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
			Die(2);
		}
		LOG(LogLevel::INFO) << "bind success";
	}
	void Start()
	{
		_isrunning = true;
		while (true)
		{
			char inbuffer[1024];
			struct sockaddr_in peer;
			socklen_t len = sizeof(peer);
			ssize_t n = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0,CONV(&peer),&len);
			if(n > 0)
			{
				// 消息内容  谁给我发的消息
				uint16_t clientpost = ::ntohs(peer.sin_port);
				std::string clientpi = ::inet_ntoa(peer.sin_addr);
				// LOG(LogLevel::DEBUG) << ::ntohs(peer.sin_port) << "网络转主机，16位";
				// LOG(LogLevel::DEBUG) << ::inet_ntoa(peer.sin_addr) << "网络转主机，字符串形式";
				inbuffer[n] = 0;
				std::string clientinfo = clientpi + ":" + std::to_string(clientpost) + "##" + inbuffer;
				LOG(LogLevel::DEBUG) << "Client say@: " << clientinfo;

				std::string echo_string = "echo# ";
				echo_string += inbuffer;
				::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,CONV(&peer),len);
			}
		}
	}
	~UdpServer()
	{
	}

private:
	int _sockfd;
	uint16_t _port;	 // 服务器未来的端口号
	// std::string _ip; // 服务器所对应的IP
	bool _isrunning; // 服务器的运行状态
};



// -----------------------------------------------------------------------------------------
// using namespace LogModule;
// const static int gsockfd = -1;
// const static std::string gdefaultip = "127.0.0.1"; // 表示本地主机
// const static uint16_t gdefaultport = 8080;		   // 设置端口号

// class UdpServer
// {
// public:
// 	UdpServer(const std::string &ip = gdefaultip, const uint16_t port = gdefaultport)
// 		: _ip(ip), _port(port), _sockfd(gsockfd), _isrunning(false)
// 	{
// 	}
// 	void InitServer()
// 	{
// 		// 创建套接字
// 		_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
// 		if (_sockfd < 0)
// 		{
// 			LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
// 			Die(1);
// 		}
// 		LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;
// 		// 2. 填充网络信息，并bind绑定
// 		// 2.1 有没有把socket信息，设置进入内核中？？没有，只是填充了结构体！
// 		struct sockaddr_in local;
// 		bzero(&local, sizeof(local));
// 		local.sin_family = AF_INET;
// 		local.sin_port = ::htons(_port);				  // 本地发送给网络 是要把端口哈发出去，要把小段变大端
// 		local.sin_addr.s_addr = ::inet_addr(_ip.c_str()); // 1. string ip->4bytes 2. network order  ip要转换成四字节，并发到网络要转换大小端
// 		// bind 设置到内核
// 		int n = bind(_sockfd, CONV(&local), sizeof(local));
// 		if (n < 0)
// 		{
// 			LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
// 			Die(2);
// 		}
// 		LOG(LogLevel::INFO) << "bind success";
// 	}
// 	void Start()
// 	{
// 		_isrunning = true;
// 		while (true)
// 		{
// 			char inbuffer[1024];
// 			struct sockaddr_in peer;
// 			socklen_t len = sizeof(peer);
// 			ssize_t n = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0,CONV(&peer),&len);
// 			if(n > 0)
// 			{
// 				// 消息内容  谁给我发的消息
// 				uint16_t clientpost = ::ntohs(peer.sin_port);
// 				std::string clientpi = ::inet_ntoa(peer.sin_addr);
// 				// LOG(LogLevel::DEBUG) << ::ntohs(peer.sin_port) << "网络转主机，16位";
// 				// LOG(LogLevel::DEBUG) << ::inet_ntoa(peer.sin_addr) << "网络转主机，字符串形式";
// 				inbuffer[n] = 0;
// 				std::string clientinfo = clientpi + ":" + std::to_string(clientpost) + "##" + inbuffer;
// 				LOG(LogLevel::DEBUG) << "Client say@: " << clientinfo;

// 				std::string echo_string = "echo# ";
// 				echo_string += inbuffer;
// 				::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,CONV(&peer),len);
// 			}
// 		}
// 	}
// 	~UdpServer()
// 	{
// 	}

// private:
// 	int _sockfd;
// 	uint16_t _port;	 // 服务器未来的端口号
// 	std::string _ip; // 服务器所对应的IP
// 	bool _isrunning; // 服务器的运行状态
// };

#endif